import { Reporter } from './reporter';
import { ErrorSubType } from '../types';

export class ErrorMonitor {
  private reporter: Reporter;
  private isListening = false;

  constructor(reporter: Reporter) {
    this.reporter = reporter;
    this.init();
  }

  /**
   * 初始化错误监听
   */
  init() {
    if (this.isListening) return;
    this.isListening = true;

    // 监听JS运行时错误
    this.listenJsError();
    // 监听资源加载错误
    this.listenResourceError();
    // 监听Promise未捕获错误
    this.listenPromiseError();
    // 监听HTTP请求错误（需配合拦截器）
    this.listenHttpError();
  }

  /**
   * JS运行时错误（同步+异步）
   */
  private listenJsError() {
    window.onerror = (message, source, lineno, colno, error) => {
      // 过滤跨域脚本错误（无详细信息）
      if (source && this.isCrossOrigin(source)) return true;

      this.reporter.push({
        type: 'error',
        subType: 'js_error' as ErrorSubType,
        message: String(message),
        source,
        lineno,
        colno,
        stack: error?.stack || ''
      });
      return true; // 阻止浏览器默认报错
    };
  }

  /**
   * 资源加载错误（img/script/css等）
   */
  private listenResourceError() {
    window.addEventListener('error', (event) => {
      const target = event.target as HTMLElement;
      // 判断是否为资源元素
      if (target.tagName.match(/^(IMG|SCRIPT|LINK|VIDEO|AUDIO)$/i)) {
        this.reporter.push({
          type: 'error',
          subType: 'resource_error' as ErrorSubType,
          tag: target.tagName.toLowerCase(),
          url: (target as HTMLImageElement).src || (target as HTMLScriptElement).src || (target as HTMLLinkElement).href,
          message: event.message || '资源加载失败'
        });
      }
    }, true); // 捕获阶段监听
  }

  /**
   * Promise未捕获错误
   */
  private listenPromiseError() {
    window.addEventListener('unhandledrejection', (event) => {
      this.reporter.push({
        type: 'error',
        subType: 'promise_error' as ErrorSubType,
        message: event.reason?.message || String(event.reason),
        stack: event.reason?.stack || ''
      });
      event.preventDefault();
    });
  }

  /**
   * HTTP请求错误（需用户手动调用，配合axios/fetch拦截器）
   */
  listenHttpError() {
    // 提供给用户的HTTP错误上报方法
    return (url: string, method: string, status: number, error: string) => {
      this.reporter.push({
        type: 'error',
        subType: 'http_error' as ErrorSubType,
        url,
        method,
        status,
        error
      });
    };
  }

  /**
   * 判断是否跨域
   */
  private isCrossOrigin(url: string): boolean {
    try {
      const parsedUrl = new URL(url);
      return parsedUrl.origin !== window.location.origin;
    } catch {
      return true;
    }
  }
}